home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiniExamples / AppKit / PaginationLab / BigView.m < prev    next >
Text File  |  1995-06-12  |  7KB  |  264 lines

  1. /* BigView.m
  2.  * Purpose: Demonstrates custom pagination.
  3.  * a BigView is a "matrix" of 3x4 rectangles, each of which is 8" x 10"
  4.  * A bigView therefore has very logical page breaks, although the Appkit by
  5.  * default won't break up the bigView on those boundaries.  This class demonstrates
  6.  * how to do this.  This class also demonstrates somewhat optimized scrolling by only
  7.  * drawing affected pages (because a page is the smallest divisible unit in this class.)
  8.  *
  9.  * You may freely copy, distribute, and reuse the code in this example.
  10.  * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  11.  * fitness for any particular use.
  12.  *
  13.  * Written by: Samuel Streeper
  14.  * Created: (04/April/91)
  15.  */
  16.  
  17. #import "BigView.h"
  18. #import "drawRect.h"
  19. #import "MyPrintInfo.h"
  20. #import <dpsclient/wraps.h>
  21. #import <math.h>
  22.  
  23. #define INCHES * 72.0
  24.  
  25. #define PAGEWIDTH (8 INCHES)
  26. #define PAGEHEIGHT (10 INCHES)
  27. #define GRIDWIDTH (1. INCHES)
  28. #define GRIDHEIGHT (1. INCHES)
  29.  
  30. #define MAXCOLUMN 3
  31. #define MAXROW 4
  32. #define PAGES (MAXCOLUMN * MAXROW)
  33.  
  34. #define min(X, Y)  ((X) < (Y) ? (X) : (Y))
  35.  
  36. @implementation BigView
  37.  
  38. static char *string[PAGES] = {
  39.     "one","two","three","four",
  40.     "five","six","seven","eight",
  41.     "nine","ten","and","more!"
  42.     };
  43.  
  44. // I could just printf these.  Nah...
  45. static char *numbers[PAGES] = {
  46.     "1","2","3","4","5","6",
  47.     "7","8","9","A","B","C"
  48.     };
  49.     
  50. - initFrame:(const NXRect *)frameRect
  51. {
  52.     // normally you would always initialize to the frame you are passed, like this:
  53.     //    [super initFrame:frameRect];
  54.     // however, I want to force all BigView intances to be the 'correct' size.
  55.     // (you usually shouldn't do this...)
  56.  
  57.     NXRect r = {0,0,(MAXCOLUMN*PAGEWIDTH),(MAXROW*PAGEHEIGHT)};
  58.     [super initFrame:&r];
  59.  
  60.     [self allocateGState];        // for faster focusing and scrolling
  61.     loadPSProcedures();            // initialize the drawing context
  62.     return self;
  63. }
  64.  
  65. // DrawSelf is used to construct the View for printing or when a portion
  66. // gets scrolled onto the screen.  It should only draw the areas that
  67. // intersect with rects.
  68. - drawSelf:(const NXRect *)rects :(int)rectCount
  69. {
  70.     int darkFlag;
  71.     int minColumn, maxColumn, minRow, maxRow;
  72.     int row, col, offset;
  73.     
  74.     if (!rectCount) return self;
  75.     minColumn = rects->origin.x / PAGEWIDTH;
  76.     maxColumn = (rects->origin.x + rects->size.width) / PAGEWIDTH;
  77.  
  78.     minRow = rects->origin.y / PAGEHEIGHT;
  79.     maxRow = (rects->origin.y + rects->size.height) / PAGEHEIGHT;
  80.     
  81.     if (maxColumn > MAXCOLUMN-1) maxColumn = MAXCOLUMN-1;
  82.     if (maxRow > MAXROW-1) maxRow = MAXROW-1;
  83.  
  84.     // Drawing is optimized to draw only the affected pages.  In this app,
  85.     // it's possible for one page to somewhat overlap another page.
  86.     // Without clipping, drawing optimization could allow a page in back to
  87.     // draw, while not telling the page in front to draw.  Clipping to rects
  88.     // insures that either the background will not draw over the foreground,
  89.     // or if it does, the foreground page will also draw
  90.     
  91.     NXRectClip(rects);
  92.     
  93.     for (col = minColumn; col <= maxColumn; col++)
  94.     {
  95.         for (row = minRow; row <= maxRow; row++)
  96.         {
  97.             offset = ((MAXROW-1)-row)*MAXCOLUMN + col;
  98.             darkFlag = ((row + col) & 1);
  99.             drawRect(col*PAGEWIDTH,row*PAGEHEIGHT,string[offset], numbers[offset], darkFlag);
  100.         }
  101.     }
  102.     return self;
  103. }
  104.  
  105. // If the extended printInfo has been set to application controlled
  106. // pagination, tell the kit we know where our pages lie.
  107. - (BOOL)knowsPagesFirst:(int *)firstPageNum last:(int *)lastPageNum
  108. {
  109.     if ([pi paginationMode] != APPCONTROLLED) return NO;
  110.     
  111.     *lastPageNum = PAGES;
  112.     return YES;
  113. }
  114.  
  115. // If we know where our pages lie, the kit will ask us for the rect
  116. // for each page.
  117. - (BOOL)getRect:(NXRect *)theRect forPage:(int)page
  118. {
  119.     int row, col;
  120.  
  121.     if (page < 1 || page > PAGES) return NO;
  122.     page--;
  123.     row = (MAXROW-1) - (page / MAXCOLUMN);
  124.     col = page % MAXCOLUMN;
  125.  
  126.     theRect->origin.x = col * PAGEWIDTH;
  127.     theRect->origin.y = row * PAGEHEIGHT;
  128.     theRect->size.width = PAGEWIDTH;
  129.     theRect->size.height = PAGEHEIGHT;
  130.     return YES;
  131. }
  132.  
  133.  
  134. // There are at least 3 good reasons to override this method:
  135. // 1) The printing rect does not appear where you desire on the paper
  136. //        so you set your own value for location
  137. // 2) The rect in aRect is not the one that you want placed, due to
  138. //        scaling by your own pagination algorithm (which is applied _after_
  139. //        this method gets invoked), or you will change
  140. //        the size with adjustPageHeight and andjustPageWidth.  I override
  141. //        this method for reason #2
  142. // 3) The kit version of this method will not horizontally center
  143. //         a rect if the View has more than 1 column, and it will not
  144. //         vertically center a rect if the View has more than 1 row.
  145. //        If you need this, it is trivial to rewrite this method to
  146. //        center the rect within the paperRect.
  147.  
  148. - placePrintRect:(const NXRect *)aRect offset:(NXPoint *)location
  149. {
  150.     NXRect myRect;
  151.     float vertScale, horScale;
  152.     NXCoord l,r,t,b;
  153.     const NXRect *paperRect;
  154.     
  155.     if ([pi paginationMode] != APPCONTROLLED)
  156.     {
  157.         [super placePrintRect:aRect offset:location];
  158.     }
  159.     else
  160.     {    
  161.         myRect = *aRect;
  162.         paperRect = [pi paperRect];
  163.         [pi getMarginLeft:&l right:&r top:&t bottom:&b];
  164.  
  165.         // calculate scaling factor so that rect will fit within margins
  166.         horScale = (paperRect->size.width - r - l)/PAGEWIDTH;
  167.         if (horScale <= 0) horScale = 1;
  168.         vertScale = (paperRect->size.height - t - b)/PAGEHEIGHT;
  169.         if (vertScale <= 0) vertScale = 1;
  170.  
  171.         realScale = min(horScale, vertScale);
  172.         myRect.size.width *= realScale;
  173.         myRect.size.height *= realScale;
  174.         
  175.         // now place the scaled rect (scaling actually happens later,
  176.         // in addToPageSetup...)
  177.  
  178.         [super placePrintRect:&myRect offset:location];
  179.     }
  180.  
  181.     return self;    
  182. }
  183.  
  184. // Note: add to page setup is called after placePrintRect.  Thus placePrintRect attempts
  185. // to place an unscaled rect.  Thus any scaling you will add here should be figured
  186. // into the placement of the print rectangle.
  187. - addToPageSetup
  188. {
  189.     [super addToPageSetup];
  190.  
  191.     if ([pi paginationMode] == APPCONTROLLED)
  192.     {
  193.         PSscale(realScale, realScale);
  194.     }
  195.  
  196.     return self;
  197. }
  198.  
  199.  
  200. // A helpful hint:  You won't be able to adjust the height if vertical pagination
  201. // is set to clip...
  202.  
  203. - adjustPageHeightNew:(float *)newBottom
  204.     top:(float)oldTop
  205.     bottom:(float)oldBottom
  206.     limit:(float)bottomLimit
  207. {
  208.     if ([pi paginationMode] == AUTOWITHHELP)
  209.     {
  210.         // caution! with normal coordinates, you need to round the height up...
  211.         * newBottom = (ceil(oldBottom/GRIDHEIGHT)) * GRIDHEIGHT;
  212.         if (*newBottom < oldBottom || *newBottom > bottomLimit)
  213.             *newBottom = oldBottom;
  214.     }
  215.     else
  216.     {
  217.         [super adjustPageHeightNew:newBottom top:oldTop bottom:oldBottom
  218.             limit:bottomLimit];
  219.     }
  220.     return self;
  221. }
  222.  
  223. // A helpful hint:  You won't be able to adjust the width if horizontal pagination
  224. // is set to clip...
  225.  
  226. - adjustPageWidthNew:(float *)newRight
  227.     left:(float)oldLeft
  228.     right:(float)oldRight
  229.     limit:(float)rightLimit
  230. {
  231.     if ([pi paginationMode] == AUTOWITHHELP)
  232.     {
  233.         * newRight = (floor(oldRight/GRIDWIDTH)) * GRIDWIDTH;
  234.         if (*newRight > oldRight || *newRight < rightLimit)
  235.             *newRight = oldRight;
  236.     }
  237.     else
  238.     {
  239.         [super adjustPageWidthNew:newRight left:oldLeft right:oldRight
  240.             limit:rightLimit];
  241.     }
  242.     return self;
  243. }
  244.  
  245. // Remember that when you print, you are outputting to a different context
  246. // than when you were drawing.  Therefore, you need to define the
  247. // procedures you will use for the printing context.
  248.  
  249. - endPrologue
  250. {
  251.     loadPSProcedures();
  252.     return [super endPrologue];
  253. }
  254.  
  255. // I do this just so I don't have to keep calling [NXApp printInfo]
  256. - setPrintInfo:newPi
  257. {
  258.     pi = newPi;
  259.     return self;
  260. }
  261.  
  262.  
  263. @end
  264.